package com.lcf.framework.utils;

import jakarta.annotation.Resource;
import lombok.Data;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 描述：redis缓存
 *
 * @author lcf
 * @since 2025/2/26 13:01
 */
@Component
public class RedisCacheUtils {
    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 缓存对象
     */
    public <T> void cache(final String key, T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 缓存对象
     */
    public <T> void cache(final String key, final T value, final Duration duration) {
        redisTemplate.opsForValue().set(key, value, duration);
    }

    /**
     * 获取缓存对象
     */
    public <T> T get(final String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 缓存list
     */
    public <T> long cacheList(final String key, final List<T> dataList) {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }

    /**
     * 获取list
     */
    public <T> List<T> getList(final String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 缓存set
     */
    public <T> void cacheSet(String key, final Set<T> values) {
        if (CollectionUtils.isEmpty(values)) {
            return;
        }

        BoundSetOperations operations = redisTemplate.boundSetOps(key);
        values.forEach(operations::add);
    }

    /**
     * 添加元素到set
     */
    public <T> void addToSet(final String key, final T... values) {
        if (ArrayUtils.isEmpty(values)) {
            return;
        }

        redisTemplate.opsForSet().add(key, values);
    }

    /**
     * 获取set中的所有元素
     */
    public <T> Set<T> getSet(final String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 检查元素是否存在于 SET 中
     */
    public <T> boolean isSetMember(final String key, final T value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * 删除 SET 中的元素
     */
    public <T> void removeFromSet(final String key, final T... values) {
        if (ArrayUtils.isEmpty(values)) {
            return;
        }

        redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * 缓存hash
     */
    public <T> void cacheHash(final String key, final Map<String, T> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 获取hash
     */
    public <T> Map<String, T> getHash(final String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取单个字段的值
     */
    public <T> T getHashValue(final String key, final String field) {
        return (T) redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 检查字段是否存在
     */
    public boolean isHashField(final String key, final String field) {
        return redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 删除hash字段
     */
    public void removeHashFields(final String key, final String... fields) {
        redisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 缓存zset
     */
    public <T> void cacheZSet(final String key, final Set<ZSetEntry<T>> values) {
        if (CollectionUtils.isEmpty(values)) {
            return;
        }

        BoundZSetOperations<String, T> operations = redisTemplate.boundZSetOps(key);
        values.forEach(entry -> operations.add(entry.getValue(), entry.getScore()));
    }

    /**
     * 添加单个元素到zset
     */
    public <T> void addToZSet(final String key, final T value, final double score) {
        redisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * 获取zset中的所有元素
     */
    public <T> Set<T> getZSet(String key) {
        return redisTemplate.opsForZSet().range(key, 0, -1);
    }

    /**
     * 获取zset中指定范围的元素
     * start起始排名（包含），从 0 开始。
     * end结束排名（包含）
     */
    public <T> Set<T> getZSetRange(final String key, final long start, final long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 按分数范围获取zset中的元素
     * 仅返回在指定分数范围内的元素值
     * min：最小分数（包含）
     * max：最大分数（包含）。
     */
    public <T> Set<T> getZSetRangeByScore(final String key, final double min, final double max) {
        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
    }

    /**
     * 按分数范围获取zset中的元素
     * 返回在指定分数范围内的元素值及其对应的分数
     * min：最小分数（包含）
     * max：最大分数（包含）。
     */
    public <T> Set<T> getZSetRangeByScoreWithScores(final String key, final double min, final double max) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
    }

    /**
     * 获取zset中指定元素的分数
     */
    public Double getZSetScore(final String key, final Object value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    /**
     * 删除zset中的元素
     */
    public <T> void removeFromZSet(final String key, final T... values) {
        if (ArrayUtils.isEmpty(values)) {
            return;
        }

        redisTemplate.opsForZSet().remove(key, values);
    }

    /**
     * 删除zset中按分数范围的元素
     * min：最小分数（包含）
     * max：最大分数（包含）。
     */
    public Long removeZSetRangeByScore(final String key, final double min, final double max) {
        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
    }

    /**
     * 删除zset中按排名范围的元素
     * start起始排名（包含），从 0 开始。
     * end结束排名（包含）
     */
    public Long removeZSetRangeByRank(final String key, final long start, final long end) {
        return redisTemplate.opsForZSet().removeRange(key, start, end);
    }

    /**
     * 设置有效时间
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 删除全部结构obj,list,set,hash,zset
     */
    public boolean del(final String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 辅助类用于存储 ZSet 的值和分数
     */
    @Data
    public static class ZSetEntry<T> {
        private final T value;
        private final double score;

        public ZSetEntry(T value, double score) {
            this.value = value;
            this.score = score;
        }
    }
}
